package fhq.hcmute.qrcode.common;

/**
 * @author Hien Nguyen Le
 * @Email: nglehien@gmail.com
 */
public enum MaskPattern {
	/**
	 * @Data: 000
	 * @Condition:(i + j) % 2 == 0
	 */
	Verion_0("000"),
	/**
	 * @Data: 001
	 * @Condition:(i % 2 == 0)
	 */
	Verion_1("001"),
	/**
	 * @Data: 010
	 * @Condition:(j % 2 == 0)
	 */
	Verion_2("010"),
	/**
	 * @Data: 011
	 * @Condition:(i + j) % 3 == 0
	 */
	Verion_3("011"),
	/**
	 * @Data: 100
	 * @Condition:((i / 2) + (j / 3)) % 2 == 0
	 */
	Verion_4("100"),
	/**
	 * @Data: 101
	 * @Condition:(i * j) % 2 + (i * j) % 3 == 0
	 */
	Verion_5("101"),
	/**
	 * @Data: 110
	 * @Condition:((i * j) % 2 + (i * j) % 3) % 2 == 0
	 */
	Verion_6("110"),
	/**
	 * @Data: 111
	 * @Condition:((i + j) % 2 + (i * j) % 3) % 2 == 0
	 */
	Verion_7("111");
	private String value;
	public static final int N1 = 3;
	public static final int N2 = 3;
	public static final int N3 = 40;
	public static final int N4 = 10;

	private MaskPattern(String data) {
		this.value = data;
	}

	public String getValue() {
		return value;
	}

	/**
	 * get Mask Pattern by ID. The Default is mask pattern 1
	 * 
	 * @param id
	 * @return
	 */
	public static MaskPattern parse(int id) {
		for (MaskPattern b : MaskPattern.values()) {
			int value = Integer.parseInt(b.value, 2);
			if (id == value) {
				return b;
			}
		}
		return Verion_0;
	}

	public static MaskPattern parse(String mask) {
		for (MaskPattern b : MaskPattern.values()) {
			if (b.value.equals(mask)) {
				return b;
			}
		}
		return Verion_0;
	}

	public int xor(int i, int j, int value) {
		switch (this) {
		case Verion_0:
			if ((i + j) % 2 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		// return value;
		case Verion_1:
			if (i % 2 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_2:
			if (j % 3 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_3:
			if ((i + j) % 3 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_4:
			if (((i / 2) + (j / 3)) % 2 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_5:
			if ((i * j) % 2 + (i * j) % 3 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_6:
			if (((i * j) % 2 + (i * j) % 3) % 2 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		case Verion_7:
			if (((i + j) % 2 + (i * j) % 3) % 2 == 0) {
				value ^= BitMatrix.TRUE;
			} else {
				value ^= BitMatrix.FALSE;
			}
			break;
		}
		if (value == 0) {
			value = BitMatrix.FALSE;
		} else {
			value = BitMatrix.TRUE;
		}
		return value;
	}

	public BitMatrix releaseMaskPattern(BitMatrix dataMatrix) {
		int dimension = dataMatrix.getModule();
		BitMatrix dataMatrix2 = new BitMatrix(dimension, dimension);
		for (int i = 0; i < dimension; i++) {
			for (int j = 0; j < dimension; j++) {
				int value = dataMatrix.get(i, j);
				value = this.xor(i, j, value);
				dataMatrix2.set(i, j, value);
			}
		}
		return dataMatrix2;
	}
}
